Skip to content

Update shared memory proposal#4620

Merged
mraleph merged 4 commits into
dart-lang:mainfrom
mraleph:update-shared-native-memory
Apr 13, 2026
Merged

Update shared memory proposal#4620
mraleph merged 4 commits into
dart-lang:mainfrom
mraleph:update-shared-native-memory

Conversation

@mraleph
Copy link
Copy Markdown
Member

@mraleph mraleph commented Jan 26, 2026

  • Mention that final variables and fields can't be late when describing deeply immutable types.
  • Add event loop and ownership APIs to Isolate.

@mraleph mraleph requested review from aam, lrhn and mkustermann January 26, 2026 13:58
@mraleph
Copy link
Copy Markdown
Member Author

mraleph commented Jan 26, 2026

@aam @lrhn @mkustermann please take a look at the APIs.

Among others, I would like to cover the following use case:

Pointer<Void> threadBody(Pointer<Void> ptr) {
  final isolate = Isolate.fork();

  isolate.runSync(() {
    // Do something on the current thread.
  });

  // Spin event loop on this thread until nothing left to do
  isolate.runEventLoopSync();

  isolate.shutdown();
}

pthread_create(..., NativeCallable.isolateGroupBound(threadBody));

Copy link
Copy Markdown
Member

@lrhn lrhn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm being pedantic because I've seen too many cases of "everybody knows what this obviously means" turning into everybody thinking it obviously means different things.

So use words and phrases consistently, internally and with existing documentation.
Don't use a new word if an existing word is already in use.
If a new concept is important, define it and give it a unique name. (And define the concepts at the user/API level, nobody else cares about the implementation.)

Comment thread working/333 - shared memory multithreading/shared_native_memory.md Outdated
Comment thread working/333 - shared memory multithreading/shared_native_memory.md
Comment thread working/333 - shared memory multithreading/shared_native_memory.md
Comment thread working/333 - shared memory multithreading/shared_native_memory.md Outdated

/// Create a new isolate in the current isolate group.
///
/// Similar to `Dart_CreateIsolateInGroup` Dart VM C API.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this line useful to a reader? (Should I go read the docs on that function. If so, link!)
If not, I don't see the relevance for a Dart user reading this API.

(If it actualy calls that function, it might be relevant information, at some abstraction level. If it's just sort-of similar to a function that I don't know and can't be bothered to look at, that's just noise.)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wish I could link to these - but we don't publish documentation for these. So the best I could do is to link to sources, which is a bit wonky.

It is hard to say whether these are useful or not - if reader is familiar with C API layer they are certainly useful because most of APIs introduced here are exposing functionality which is available through C API.

I would prefer to keep these here for the purpose of spec review / but we can strip them later when landing actual code.

Comment thread working/333 - shared memory multithreading/shared_native_memory.md Outdated
Comment thread working/333 - shared memory multithreading/shared_native_memory.md Outdated
Comment thread working/333 - shared memory multithreading/shared_native_memory.md Outdated
/// executing code in the target isolate.
///
/// Throws [TimeoutException] if [timeout] has been reached while waiting
/// to acquire exclusive access to the isolate.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All these thread-based members of isolate, would it make sense to put them somewhere else than in Isolate, like in dart:isolate_threads, where they could be extension members on Isolate if we really want them there.

Do we expect most people who use isolates to also want to use these thread-based functions, or will they clutter the API for the "normal" uses of Isolate and enocurage people to use them who really shoudn't?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, these are fairly low-level. Maybe we need to introduce dart:threading?

Comment thread working/333 - shared memory multithreading/shared_native_memory.md Outdated
/// thus can't be entered from a different thread. See
/// [markOwnedByCurrentThread] and [isOwnedByCurrentThread].
///
/// Throws [ArgumentError] if the target isolate belongs to another
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can an isolate obtain an Isolate object from a different group?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spawnUri gives you an Isolate object in a different group.

Comment thread working/333 - shared memory multithreading/shared_native_memory.md Outdated
/// between turns of its event loop, when no other thread is
/// executing code in the target isolate.
///
/// Throws [TimeoutException] if [timeout] has been reached while waiting
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If an isolate is dead but someone uses the Isolate object, then what happens? Will an operation timeout will it throw an error?

I guess Isolate is a weak reference to an actual isolate. So using it has to turn the weak reference into a strong reference using some global data structure with locking (bit like PortMap).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If isolate dies operations with it should throw an error - Isolate is just a port number and yeah all operations with it are based on that. We can guard against dead isolates to some extent - though if port number gets reused you will get strange effects. But I am not sure this can be fully resolved.

/// * integrate isolate's event loop with other event loop by registering
/// message callback ([Isolate.onMessage]) and draining pending messages
/// ([Isolate.handleMessage]).
external static Isolate fork({String? debugName});
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find the name fork strange as a C fork() call actually gives you a copy of the state of the process, there's no clearing of state to some initial state happening.

Furthermore from the motivating example in #4620 (comment) it seems that the caller may not even be an isolate with state. So when a Thread (aka shared isolate) calls Isolate.fork() it gets an isolate with freshly initialized state.

Why not call it Isolate.create() instead?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to Isolate.create.

@knopp
Copy link
Copy Markdown

knopp commented Feb 23, 2026

 isolate.runEventLoopSync();

In addition to isolate.runEventLoopSync(); I'd like to have a method to "poll" the event loop, i.e. bock until there is event scheduled and then processes the event.

If we ever wanted to for example reimplement the embedder in Dart, we'd need this for resize synchronization (i.e. we want to be able run the dart event loop in a blocking way until surface with appropriate size is generated). Right now we have an implementation for this per platform (a custom CFRunLoopMode on macOS or polling the loop on windows). This only processes Flutter messages and ignores the platform events.

@mraleph
Copy link
Copy Markdown
Member Author

mraleph commented Feb 23, 2026

@knopp polling is implementable on top of onMessage and handleMessage AFAIK.

@knopp
Copy link
Copy Markdown

knopp commented Feb 23, 2026

Not sure what's the good way to submit feedback to the proposal, just something I've noticed:

NativeCallable.isolateLocal: native caller must have an exclusive access to an isolate in which callback was created. This type of callback works if Dart calls C and C calls back into Dart synchronously. It also works if caller uses VM C API for entering isolates (e.g.Dart_EnterIsolate/Dart_ExitIsolate).

Just a nit, but after dart-lang/sdk#61623, NativeCallable.isolateLocal will enter the isolate as long as current thread owns the isolate.

@mraleph
Copy link
Copy Markdown
Member Author

mraleph commented Mar 3, 2026

@lrhn @mkustermann I think I addressed most of comments.

I think the main question that remains is whether or not to move low-level isolate members to a separate library.

I am starting to think that maybe dart:threading is an appropriate name for it. Any other ideas?

Comment thread working/333 - shared memory multithreading/shared_native_memory.md Outdated
@mraleph
Copy link
Copy Markdown
Member Author

mraleph commented Apr 13, 2026

I am going to land this and @aam is working to implementing the prototype. We have few remaining unanswered questions (e.g. where should new methods reside), but we can address them later.

@mraleph mraleph merged commit f1776bb into dart-lang:main Apr 13, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants